﻿@using SimpleIdServer.IdServer.Authenticate.Handlers;
@using SimpleIdServer.IdServer.Website.Resources;
@using SimpleIdServer.IdServer.Website.Shared.Dialogs
@using SimpleIdServer.IdServer.Website.Stores.ClientStore;
@using SimpleIdServer.IdServer.Website.Stores.UserStore;
@inherits Fluxor.Blazor.Web.Components.FluxorLayout
@inject NotificationService notificationService
@inject NavigationManager navigationManager
@inject ContextMenuService contextMenuService
@inject DialogService dialogService
@layout MainLayout
@inject IState<UpdateClientState> updateClientState
@inject IDispatcher dispatcher

<RadzenTemplateForm Submit=@UpdateCredential TItem="UpdateClientCredential" Data=@updateClientCredential>
    <!-- Authentication method -->
    <div>
        <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.AuthenticationMethod</RadzenText>
        <RadzenDropDown Name="AuthMethod" Class="w-100"
        Data=@clientCredentialInfos
        TValue="string"
        @bind-Value=@updateClientCredential.AuthMethod
        TextProperty="Name" ValueProperty="AuthMethod" />
        <RadzenRequiredValidator Component="AuthMethod" Text="@Global.AuthenticationMethodRequired"></RadzenRequiredValidator>
    </div>
    @if (updateClientCredential != null && !string.IsNullOrWhiteSpace(updateClientCredential.AuthMethod))
    {        
        <div class="text-muted mt-1">
            <RadzenIcon Icon="info" />
            @(clientCredentialInfos.Single(c => c.AuthMethod == updateClientCredential.AuthMethod).Description)
        </div>
    }

    @switch (updateClientCredential.AuthMethod)
    {
        case OAuthClientSecretPostAuthenticationHandler.AUTH_METHOD:
        case OAuthClientSecretBasicAuthenticationHandler.AUTH_METHOD:
            <!-- Secret-->
            <div>
                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.ManageClientSecrets</RadzenText>
                <RadzenButton class="mb-1" Click="@(async (args) => await AddSecret())" Icon="add" Text="@Global.Add" ButtonStyle="ButtonStyle.Primary" Size="ButtonSize.Medium"></RadzenButton>
                <RadzenDataGrid Data="Secrets" TItem="SelectableClientSecret"
                AllowSorting="true">
                    <Columns>
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Sortable="true" Width="80px">
                            <HeaderTemplate>
                                <RadzenCheckBox @bind-Value=@selectAll Change="@(args => ToggleAll(args))" TValue="bool" />
                            </HeaderTemplate>
                            <Template Context="data">
                                <RadzenCheckBox @bind-Value=@data.IsSelected Change="@(args => ToggleChanged(args, data))" TValue="bool" />
                            </Template>
                        </RadzenDataGridColumn>
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Property="ClientSecret.Alg" Sortable="false" Title="@Global.HashAlgorithm" Width="80px">
                            <Template Context="data">
                                <RadzenBadge Text="@(Enum.GetName(typeof(HashAlgs), data.ClientSecret.Alg))" BadgeStyle="BadgeStyle.Info"></RadzenBadge>                                
                            </Template>
                        </RadzenDataGridColumn>
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Property="ClientSecret.CreateDateTime" Sortable="true" Title="@Global.CreatedAt" Width="80px" SortOrder="SortOrder.Descending" />
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Property="ClientSecret.ExpirationDateTime" Sortable="true" Title="@Global.ExpirationTime" Width="80px" />
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Property="ClientSecret.IsActive" Sortable="true" Title="@Global.Status" Width="80px">
                            <Template Context="data">
                                <RadzenBadge BadgeStyle=@(data.ClientSecret.IsInactive ? BadgeStyle.Danger : BadgeStyle.Success) Text=@(!data.ClientSecret.IsInactive ? Global.Active : (!data.ClientSecret.IsActive ? Global.Inactive: Global.Expired ))></RadzenBadge>
                            </Template>
                        </RadzenDataGridColumn>
                        <RadzenDataGridColumn TItem="SelectableClientSecret" Sortable="true" Title="@Global.ExpirationTime" Width="80px">
                            <Template Context="data">
                                <RadzenButton Icon="more_vert" Click="@(args => ShowMoreContextMenu(data, args))" />
                            </Template>
                        </RadzenDataGridColumn>
                    </Columns>
                </RadzenDataGrid>
            </div>
            break;
        case OAuthClientTlsClientAuthenticationHandler.AUTH_METHOD:
            <!-- TlsClientAuthSubjectDN -->
            <div>
                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.SubjetDistinguishedName</RadzenText>
                <RadzenTextBox Name="TlsClientAuthSubjectDN" @bind-Value="@updateClientCredential.TlsClientAuthSubjectDN" Class="w-100"></RadzenTextBox>
            </div>
            <!-- TlsClientAuthSanDNS -->
            <div>
                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.Dns</RadzenText>
                <RadzenTextBox Name="TlsClientAuthSanDNS" @bind-Value="@updateClientCredential.TlsClientAuthSanDNS" Class="w-100"></RadzenTextBox>
            </div>
            <!-- TlsClientAuthSanEmail -->
            <div>
                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.Email</RadzenText>
                <RadzenTextBox Name="TlsClientAuthSanEmail" @bind-Value="@updateClientCredential.TlsClientAuthSanEmail" Class="w-100"></RadzenTextBox>
            </div>
            <!-- TlsClientAuthSanIP -->
            <div>
                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.Ip</RadzenText>
                <RadzenTextBox Name="TlsClientAuthSanIP" @bind-Value="@updateClientCredential.TlsClientAuthSanIP" Class="w-100"></RadzenTextBox>
            </div>
            break;
    }

    <SidAuthorizeView Roles=@("/clients/manage")>
        <Authorized>
            <RadzenButton class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Text="@(updateClientState.Value.IsUpdating ? Global.Updating : Global.Save)" Disabled="@(updateClientState.Value.IsUpdating)" />
        </Authorized>
    </SidAuthorizeView>
</RadzenTemplateForm>

@code {
    record UpdateClientCredential
    {
        public string AuthMethod { get; set; } = null!;
        public string? TlsClientAuthSubjectDN { get; set; } = null;
        public string? TlsClientAuthSanDNS { get; set; } = null;
        public string? TlsClientAuthSanEmail { get; set; } = null;
        public string? TlsClientAuthSanIP { get; set; } = null;
    }

    record ClientCredentialInfo
    {
        public string Name { get; set; } = null!;
        public string AuthMethod { get; set; } = null!;
        public string Description { get; set; } = null!;
    }

    bool selectAll;
    List<SelectableClientSecret> Secrets;
    UpdateClientCredential updateClientCredential = new UpdateClientCredential();
    List<ClientCredentialInfo> clientCredentialInfos = new List<ClientCredentialInfo>
    {
        new ClientCredentialInfo { AuthMethod = OAuthClientSecretPostAuthenticationHandler.AUTH_METHOD, Name = Global.ClientSecretPostName, Description = Global.ClientSecretPostDescription },
        new ClientCredentialInfo { AuthMethod = OAuthClientSecretBasicAuthenticationHandler.AUTH_METHOD, Name = Global.ClientSecretBasicName, Description = Global.ClientSecretBasicDescription },
        new ClientCredentialInfo { AuthMethod = OAuthClientPrivateKeyJwtAuthenticationHandler.AUTH_METHOD, Name = Global.SignedJwtName, Description = Global.SignedJwtDescription },
        new ClientCredentialInfo { AuthMethod = OAuthClientSecretJwtAuthenticationHandler.AUTH_METHOD, Name = Global.SignedJwtClientSecretName, Description = Global.SignedJwtClientSecretDescription },
        new ClientCredentialInfo { AuthMethod = OAuthClientSelfSignedTlsClientAuthenticationHandler.AUTH_METHOD, Name = Global.SelfSignedX509CertificateName, Description = Global.SelfSignedX509CertificateDescription },
        new ClientCredentialInfo { AuthMethod = OAuthClientTlsClientAuthenticationHandler.AUTH_METHOD, Name = Global.X509CertificateName, Description = Global.X509CertificateDescription }
    };

    [Parameter]
    public SimpleIdServer.IdServer.Domains.Client Client { get; set; }

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);
        if (firstRender)
        {
            SubscribeToAction<UpdateClientCredentialsSuccessAction>((act) =>
            {
                notificationService.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = Global.ClientCredentialsUpdated });
                StateHasChanged();
            });
            SubscribeToAction<DeleteClientSecretsSuccessAction>((act) =>
            {
                notificationService.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = Global.ClientSecretsRemoved });
                StateHasChanged();
            });
        }
    }

    protected override void OnParametersSet()
    {
        base.OnParametersSet();
        if (Client == null) return;
        updateClientCredential.AuthMethod = Client.TokenEndPointAuthMethod;
        updateClientCredential.TlsClientAuthSubjectDN = Client.TlsClientAuthSubjectDN;
        updateClientCredential.TlsClientAuthSanDNS = Client.TlsClientAuthSanDNS;
        updateClientCredential.TlsClientAuthSanEmail = Client.TlsClientAuthSanEmail;
        updateClientCredential.TlsClientAuthSanIP = Client.TlsClientAuthSanIP;
        Secrets = Client.Secrets.Select(s => new SelectableClientSecret
        {
            ClientSecret = s,
            IsSelected = false
        }).ToList();
    }

    void UpdateCredential(UpdateClientCredential updateClientCred)
    {
        var act = new UpdateClientCredentialsAction 
        { 
            Id = Client.Id,
            AuthMethod = updateClientCred.AuthMethod, 
            ClientId = Client.ClientId,
            TlsClientAuthSubjectDN = updateClientCred.TlsClientAuthSubjectDN,
            TlsClientAuthSanDNS = updateClientCred.TlsClientAuthSanDNS,
            TlsClientAuthSanEmail = updateClientCred.TlsClientAuthSanEmail,
            TlsClientAuthSanIP = updateClientCred.TlsClientAuthSanIP
        };
        dispatcher.Dispatch(act);
    }

    async Task AddSecret()
    {
        await dialogService.OpenAsync<AddClientSecretDialog>(Global.AddClientSecret, new Dictionary<string, object>
        {
            { nameof(AddClientSecretDialog.Id), Client.Id }
        }, new DialogOptions
        {
            Width = "700px",
            Height = "512px",
            Resizable = true,
            Draggable = true
        });
    }

    void ToggleAll(bool isSelected)
    {
        foreach(var secret in Secrets)
        {
            secret.IsSelected = isSelected;
        }
    }

    void ToggleChanged(bool isSelected, SelectableClientSecret secret)
    {
        Secrets.Single(s => s.ClientSecret == secret.ClientSecret).IsSelected = isSelected;
    }

    void ShowMoreContextMenu(SelectableClientSecret secret, MouseEventArgs args)
    {
        var ids = Secrets.Where(s => s.IsSelected).Select(s => s.ClientSecret.Id).ToList();
        if (!ids.Contains(secret.ClientSecret.Id))
        {
            ids.Add(secret.ClientSecret.Id);
        }

        contextMenuService.Open(args, new List<ContextMenuItem>
        {
            new ContextMenuItem { Text = "Delete", Value = 1 }
        }, (a) =>
        {
            if (a.Value.Equals(1))
            {
                var act = new DeleteClientSecretsAction { Id = Client.Id, SecretIds = ids };
                dispatcher.Dispatch(act);
                contextMenuService.Close();
            }
        });
    }

    public class SelectableClientSecret
    {
        public bool IsSelected { get; set; }
        public ClientSecret ClientSecret { get; set; } = null!;
    }
}